﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Commands.Logging;
using Microsoft.Win32;

namespace Commands.Scheduling
{
    /// <summary>
    /// Class responding for checking commands source and suspending.
    /// </summary>
    internal class TimersManager
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="schedule">Schedule with intervals.</param>
        /// <param name="check">Function for checking.</param>
        public TimersManager(ICommandManager manager)
        {
            // Subscribe to system power mode changed event, to know when system is going to 
            // suspend/wake up.
            SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(_PowerModeChanged);
            // Need to unsubscribe from this system event, to escape memory leaks.
            AppDomain.CurrentDomain.ProcessExit += 
                (_,__) => SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(_PowerModeChanged);

            _schedule = manager.Schedule;

            _suspendTimerObj = new SuspendTimer(_schedule);

            _InitCheckTimer(_schedule, manager);
        }

        #region Private members

        /// <summary>
        /// Init timer responsible for checking.
        /// </summary>
        /// <param name="schedule">Schedule with intervals.</param>
        /// <param name="check">Checking function.</param>
        private void _InitCheckTimer(ISchedule schedule, ICommandManager manager)
        {
            // TODO make another timer?
            _checkTimer = new System.Timers.Timer();
            _checkTimer.Elapsed +=
                (_, __) =>
                {
                    if (_schedule.AutoCheckEnabled)
                        manager.GetAndExecute();

                    // Update next check time property.
                    _schedule.NextCheckTime = DateTime.Now.AddMilliseconds(_checkTimer.Interval);
                };

            // Update timer interval on settings changing.
            schedule.CheckSettingsChanged += () => _SetCheckTimerPeriod(schedule.CheckInterval); 

            _SetCheckTimerPeriod(schedule.CheckInterval);
        }

        private void _SetCheckTimerPeriod(TimeSpan newPeriod)
        {
            _checkTimer.Interval = newPeriod.TotalMilliseconds;
            _schedule.NextCheckTime = DateTime.Now.Add(newPeriod);
            _checkTimer.Start();
        }

        private void _PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            // Computer resume it work.
            if (e.Mode == PowerModes.Resume)
            {
                // Simulate user activity, so that computer would be suspended only after some time.
                SystemIdleInformator.SimulateUserActivity();

                // Schedule suspend.
                _suspendTimerObj.ScheduleSuspend();

                // Start check timer, update next check time property.
                _checkTimer.Start();
                _schedule.NextCheckTime = DateTime.Now.AddMilliseconds(_checkTimer.Interval);
            }
            else if (e.Mode == PowerModes.Suspend)
                _checkTimer.Stop();
        }

        private ISchedule _schedule;

        private System.Timers.Timer _checkTimer;
        private SuspendTimer _suspendTimerObj;

        #endregion
    }
}